package cn.xiuxius.embedded.config;

import cn.xiuxius.embedded.config.validator.ConfigValidator;
import cn.xiuxius.embedded.keil.MemoryModel;
import cn.xiuxius.embedded.keil.RTOS;
import cn.xiuxius.embedded.model.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;


import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Map;

@Slf4j
@Getter
@Setter
public class EasyYamlConfig {

    private EasyYamlVersion version;
    private EasyStcProject easyStcProject;
    private KeilProject keilProject;
    private Stcgl stcgl;

    private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory())
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);


    public static EasyYamlConfig load() {
        return load(Paths.get("easy-stc.yml"));
    }

    public static EasyYamlConfig load(String projectPath) {
        return load(Paths.get(projectPath, "easy-stc.yml"));
    }

    public static EasyYamlConfig load(Path configPath) {
        if (!Files.exists(configPath)) {
            log.error("Config file does not exist: {}", configPath);
            return null;
        }
        try (InputStream input = Files.newInputStream(configPath)) {
            EasyYamlConfig config = mapper.readValue(input, EasyYamlConfig.class);
            // 校验版本必须是 V1_0_0
            if (config == null) {
                log.error("Config file is empty or invalid.");
                return null;
            }
            EasyYamlVersion v = config.getVersion();
            if (v == null) {
                v = EasyYamlVersion.V1_0_1;
            }

            ConfigValidator validator = ConfigValidator.getValidator(v);

            try {
                validator.validate(config);
            } catch (IllegalArgumentException e) {
                log.error("Config file is invalid: {}", e.getMessage());
                return null;
            }
            return config;
        } catch (IOException | IllegalArgumentException e) {
            log.error("Failed to load easy-stc.yml from path: {}", configPath, e);
            return null;
        }
    }

    public static EasyYamlConfig initSave(String projectPath, String projectName, String uvprojPath) {
        Path targetPath = Paths.get(projectPath, "easy-stc.yml");

        try (InputStream inputStream = EasyYamlConfig.class.getResourceAsStream("/easy-stc.yml")) {
            if (inputStream == null) {
                log.error("Template file '/easy-stc.yml' not found in resources.");
                return null;
            }

            // 读取模板为字符串
            String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);


            uvprojPath = uvprojPath.replace("\\", "/");

            if (!uvprojPath.startsWith("./")) {
                uvprojPath = "./" + uvprojPath;
            }

            // 替换占位符
            content = content.replace("${projectName}", projectName)
                    .replace("${uvprojPath}", uvprojPath);

            // 确保目录存在
            Files.createDirectories(targetPath.getParent());

            // 写入目标文件
            Files.writeString(targetPath, content,
                    StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

            log.info("Template config saved to '{}'", targetPath);

            return load(targetPath);
        } catch (IOException e) {
            log.error("Failed to initialize easy-stc.yml from template", e);
            return null;
        }
    }


    @Getter
    @Setter
    public static class EasyStcProject {
        private String name;
    }

    @Getter
    @Setter
    public static class KeilProject {
        private String rootPath;
        private String uvprojPath;
        private RTOS rtos;
        private List<Map<String, Group>> groups;
        private List<String> includes;
        private Build build;
    }


    @Getter
    @Setter
    public static class Group {
        private String path;
    }

    @Getter
    @Setter
    public static class Build {
        private MemoryModel memoryModel;
        private boolean genHex;
        private List<String> linkSuffix;
    }

    @Getter
    @Setter
    public static class Stcgl {
        private STCFlashOptionType stcType;
        private StringFlashOptionType port;
        private boolean advance;
        private AdvanceConfig advanceConfig;
    }

    @Getter
    @Setter
    public static class AdvanceConfig {
        private BooleanFlashOptionType eepromEraseEnabled;
        private IntegerFlashOptionType userProgramEeprom;
        private PorResetFlashOptionType porResetDelay;
        private LMHFlashOptionType cpuCoreVoltage;
        private BooleanFlashOptionType watchdogPorEnabled;
        private IntegerFlashOptionType watchdogPrescale;
        private BooleanFlashOptionType bslPindetectEnabled;
        private BooleanFlashOptionType resetPinEnabled;
        private BooleanFlashOptionType aleEnabled;
        private BooleanFlashOptionType uart1Remap;
        private BooleanFlashOptionType epwmOpenDrain;
        private BooleanFlashOptionType clockGain;
        private BooleanFlashOptionType xramEnabled;
        private ClockSourceFlashOptionType clockSource;
        private IntegerFlashOptionType oscillatorStableDelay;
        private BooleanFlashOptionType watchdogStopIdle;
        private IntegerFlashOptionType lowVoltageThreshold;
        private BooleanFlashOptionType eepromLvdInhibit;
        private LHFlashOptionType rstoutPorState;
        private BooleanFlashOptionType uart2Passthrough;
        private Uart2PinFlashOptionType uart2PinMode;
    }

}
